package net.pws.common.security.spi.resource;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import net.pws.common.util.StringUtils;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;


public class ResourceDefinitionXmlParser implements
                                            ResourceDefinitionParser {
    
    public Resource[] parse(File file) {
        try {
            SAXReader reader = new SAXReader();
            Document document = reader.read(file);
            return parse(document);
        }
        catch (DocumentException e) {
            throw new ResourceDefinitionParseException(e);
        }
    }
    
    public Resource[] parse(InputStream inputStream) {
        try {
            SAXReader reader = new SAXReader();
            Document document = reader.read(inputStream);
            return parse(document);
        }
        catch (DocumentException e) {
            throw new ResourceDefinitionParseException(e);
        }
    }
    
    public Resource[] parse(String text) {
        try {
            SAXReader reader = new SAXReader();
            Document document = reader.read(new ByteArrayInputStream(text.getBytes("UTF-8")));
            return parse(document);
        }
        catch (Exception e) {
            throw new ResourceDefinitionParseException(e);
        }
    }
    
    private Resource[] parse(Document document) {
        List<Resource> result = new ArrayList<Resource>();
        
        for (Iterator iterator = document.selectNodes("//resources/menu")
                                         .iterator(); iterator.hasNext();) {
            Element element = (Element) iterator.next();
            
            Resource resource = parse(element);
            resource.setType(Resource.MENU);
            result.add(resource);
            
            parse(element, resource);
        }
        return (Resource[]) result.toArray(new Resource[0]);
    }
    
    private void parse(Element parentElement, Resource parentResource) {
        
        for (Iterator iterator = parentElement.elementIterator(); iterator.hasNext();) {
            Element element = (Element) iterator.next();
            
            String type = element.getName();
            if (!Resource.MENU.equals(type) && !Resource.OPERATION.equals(type)) {
                throw new ResourceDefinitionParseException("Unsupported element " + element.getPath());
            }
            
            Resource resource = parse(element);
            resource.setType(type);
            parentResource.addChild(resource);
            
            parse(element, resource);
        }
    }
    
    private Resource parse(Element element) {
        Resource resource = new Resource();
        
        String id = element.attributeValue("id");
        if (StringUtils.isEmpty(id)) {
            throw new ResourceDefinitionParseException("Attribute[@id] at " + element.getPath()
                                                       + " is null!");
        }
        String name = element.attributeValue("name");
        if (StringUtils.isEmpty(name)) {
            throw new ResourceDefinitionParseException("Attribute[@name] at " + element.getPath()
                                                       + "[@id="
                                                       + id
                                                       + "] is null!");
        }
        String url = element.attributeValue("url");
        if (StringUtils.isEmpty(url)) {
            throw new ResourceDefinitionParseException("Attribute[@url] at " + element.getPath()
                                                       + "[@id="
                                                       + id
                                                       + "] is null!");
        }
        
        resource.setId(id);
        resource.setCode(id);
        resource.setName(name);
        resource.setUrl(url);
        return resource;
    }
    
    public static void main(String[] args) throws Exception {
        ResourceDefinitionXmlParser parser = new ResourceDefinitionXmlParser();
        
        Resource[] resources = parser.parse(ResourceDefinitionXmlParser.class.getClassLoader()
                                                                                 .getResourceAsStream("application.resource.xml"));
        System.out.println(resources.length);
    }
    
}
